/*
 * Depstruct.cpp
 *
 *  Created on: Dec 18, 2014
 *      Author: Phong
 */

#include "Depstruct.h"
#include "Deptree.h"
#include "Utils.h"

using namespace std;

Depstruct::~Depstruct() {
    delete[] word;
    delete[] pos;
    delete[] cap;
    delete[] head;
    delete[] deprel;
    delete[] nDeps;
    for (int i = 0; i < nWords; i++)
        delete[] dep[i];
    delete[] dep;
}

void Depstruct::free(Depstruct *ds) {
    ds->refCount--;
    if (ds->refCount == 0) delete ds;
}

Depstruct::Depstruct(vector<int*>& input, vector<string>& tks){
	nWords	= (int)input.size() + 1;
	word	= new int[nWords]();
	pos		= new int[nWords]();
	cap		= new int[nWords]();
	head	= new int[nWords]();
	deprel	= new int[nWords]();
	nDeps	= new int[nWords]();
	dep		= new int*[nWords];
	for (int i = 0; i < nWords; i++) {
		dep[i] = new int[nWords]();
	}

	tokens = tks;

	// ROOT
	word[0] = pos[0] = cap[0] = deprel[0] = 0; // fake values for ROOT

	int i = 1;
	for(int* row : input) {
		word[i]		= row[0];
		pos[i]		= row[1];
		cap[i]		= row[4];
		head[i]		= row[2];
		deprel[i]	= row[3];

		// if not ROOT
		int hid = head[i];
		if (hid > -1) {
			dep[hid][nDeps[hid]] = i;
			nDeps[hid]++;
		}
		i++;
	}
    
    refCount = 1;
}

Depstruct* Depstruct::share() {
    refCount++;
    return this;
}

Depstruct* Depstruct::create(vector<string>& strlist,
		Dictionary* vocaDic, Dictionary* posDic, Dictionary* deprelDic) {
	vector<int*> input;
	vector<string> tokens;
    
	tokens.push_back("ROOT");
	// set mocking value for ROOT

	for (string str : strlist){
		vector<string> comps = Utils::splitStringWoRegex(str, "\t");
		tokens.push_back(comps[1]);
		int* row = new int[5] {	vocaDic->getId(comps[1]),
			posDic->getId(comps[4]),
			stoi(comps[6]),
			deprelDic->getId(comps[7]),
			vocaDic->getCapFeat(comps[1]) };
		input.push_back(row);
	}

    Depstruct* ret = new Depstruct(input, tokens);
	for (int* row : input) delete row;

	return ret;
}

Deptree* Depstruct::toDepTree() {
	Deptree* tree = new Deptree(nWords);
	toDepTree(0, 0, tree);
	tree->ds = this->share();
	return tree;
}

string Depstruct::toString(Dictionary* posDic, Dictionary* deprelDic) {
    string str;
	for (int i = 1; i < nWords; i++) {
		str += to_string(i) + "\t"
				+ tokens[i] + "\t"
				+ "_\t" + "_\t"
				+ posDic->id2word[pos[i]] + "\t"
				+ "_\t"
				+ to_string(head[i]) + "\t"
				+ deprelDic->id2word[deprel[i]] + "\n";
	}
	return str;
}

int Depstruct::toDepTree(int id, int node, Deptree* tree) {
	int n = nDeps[id];
	tree->word[node] = word[id];
	tree->pos[node] = pos[id];
	tree->cap[node] = cap[id];
	tree->deprel[node] = deprel[id];

	if (n == 0) node++;
	else{
		int curNode = node + 1;
		for (int i = 0; i < n; i++) {
			if (dep[id][i] < id) {
				tree->children[node][0][i] = curNode;
				tree->nChildren[node][0]++;
			}
			else {
				tree->children[node][1][i-tree->nChildren[node][0]] = curNode;
				tree->nChildren[node][1]++;

			}
			tree->parent[curNode] = node;

			if (dep[id][i] < id) 	tree->dir[curNode] = 0;
			else 					tree->dir[curNode] = 1;

			curNode = toDepTree(dep[id][i], curNode, tree);
		}

		node = curNode;
	}

	return node;
}

